msg_tool\scripts\musica/
sc.rs1use crate::scripts::base::*;
3use crate::types::*;
4use crate::utils::encoding::*;
5use anyhow::Result;
6use std::io::Write;
7
8#[derive(Debug)]
9pub struct MusicaBuilder {}
11
12impl MusicaBuilder {
13 pub fn new() -> Self {
15 MusicaBuilder {}
16 }
17}
18
19impl ScriptBuilder for MusicaBuilder {
20 fn default_encoding(&self) -> Encoding {
21 Encoding::Cp932
22 }
23
24 fn build_script(
25 &self,
26 buf: Vec<u8>,
27 _filename: &str,
28 encoding: Encoding,
29 _archive_encoding: Encoding,
30 config: &ExtraConfig,
31 _archive: Option<&Box<dyn Script>>,
32 ) -> Result<Box<dyn Script>> {
33 Ok(Box::new(MusicaScript::new(buf, encoding, config)?))
34 }
35
36 fn extensions(&self) -> &'static [&'static str] {
37 &["sc"]
38 }
39
40 fn script_type(&self) -> &'static ScriptType {
41 &ScriptType::Musica
42 }
43}
44
45#[derive(Debug)]
46pub struct MusicaScript {
47 lines: Vec<Vec<String>>,
48}
49
50impl MusicaScript {
51 pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
52 let decoded = decode_to_string(encoding, &buf, true)?;
53 let mut lines = Vec::new();
54 for line in decoded.lines() {
55 let parts: Vec<String> = line.split(' ').map(|s| s.to_string()).collect();
56 lines.push(parts);
57 }
58 Ok(MusicaScript { lines })
59 }
60}
61
62impl Script for MusicaScript {
63 fn default_output_script_type(&self) -> OutputScriptType {
64 OutputScriptType::Json
65 }
66
67 fn default_format_type(&self) -> FormatOptions {
68 FormatOptions::None
69 }
70
71 fn extract_messages(&self) -> Result<Vec<Message>> {
72 let mut messages = Vec::new();
73 for parts in &self.lines {
74 if parts.is_empty() {
75 continue;
76 }
77 if parts[0] == ".message" && parts.len() >= 5 {
79 let name_index = parts.len() - 2;
80 let text_index = parts.len() - 1;
81 let name = parts[name_index].clone();
82 let text = parts[text_index].clone();
83 let message = Message {
84 name: if name.is_empty() { None } else { Some(name) },
85 message: text,
86 };
87 messages.push(message);
88 }
89 }
90 Ok(messages)
91 }
92
93 fn import_messages<'a>(
94 &'a self,
95 messages: Vec<Message>,
96 file: Box<dyn WriteSeek + 'a>,
97 _filename: &str,
98 encoding: Encoding,
99 replacement: Option<&'a ReplacementTable>,
100 ) -> Result<()> {
101 let mut writer = std::io::BufWriter::new(file);
102 let mut mes = messages.iter();
103 let mut me = mes.next();
104 for parts in &self.lines {
105 let mut parts = parts.clone();
106 if parts.is_empty() {
107 writeln!(writer)?;
108 continue;
109 }
110 if parts[0] == ".message" && parts.len() >= 5 {
111 let m = match me {
112 Some(m) => m,
113 None => return Err(anyhow::anyhow!("Not enough messages to import.")),
114 };
115 let name_index = parts.len() - 2;
116 let text_index = parts.len() - 1;
117 if !parts[name_index].is_empty() {
118 let mut name = match &m.name {
119 Some(n) => n.clone(),
120 None => {
121 return Err(anyhow::anyhow!(
122 "Message name is missing for message: {}",
123 m.message
124 ));
125 }
126 };
127 if let Some(repl) = replacement {
128 for (k, v) in &repl.map {
129 name = name.replace(k, v);
130 }
131 }
132 parts[name_index] = name.replace(' ', "\u{3000}");
133 }
134 let mut text = m.message.clone();
135 if let Some(repl) = replacement {
136 for (k, v) in &repl.map {
137 text = text.replace(k, v);
138 }
139 }
140 parts[text_index] = text.replace(' ', "\u{3000}");
141 me = mes.next();
142 }
143 let line = parts.join(" ");
144 let d = encode_string(encoding, &line, false)?;
145 writer.write_all(&d)?;
146 writeln!(writer)?;
147 }
148 if me.is_some() || mes.next().is_some() {
149 return Err(anyhow::anyhow!("Too many messages to import."));
150 }
151 writer.flush()?;
152 Ok(())
153 }
154}